"""
配置存储模块
负责数据库配置和AI配置的持久化存储
"""

import json
import os
import logging
from typing import Dict, Any, Optional
from datetime import datetime
import threading
try:
    from cryptography.fernet import Fernet
    HAS_CRYPTOGRAPHY = True
except ImportError:
    HAS_CRYPTOGRAPHY = False
import base64

from config.database_config import DatabaseConfig, DatabaseType, db_config_manager
from config.ai_config import AIModelConfig, AIModelType, ai_config_manager


class ConfigStorage:
    """配置存储管理器"""
    
    def __init__(self, storage_dir: str = "data"):
        self.storage_dir = storage_dir
        self.db_config_file = os.path.join(storage_dir, "database_configs.json")
        self.ai_config_file = os.path.join(storage_dir, "ai_configs.json")
        self.key_file = os.path.join(storage_dir, ".config_key")
        self.logger = logging.getLogger(__name__)
        self.lock = threading.RLock()
        
        # 确保存储目录存在
        os.makedirs(storage_dir, exist_ok=True)
        
        # 初始化加密密钥
        self._init_encryption_key()
    
    def _init_encryption_key(self):
        """初始化加密密钥"""
        try:
            if HAS_CRYPTOGRAPHY:
                if os.path.exists(self.key_file):
                    with open(self.key_file, 'rb') as f:
                        self.encryption_key = f.read()
                else:
                    # 生成新的加密密钥
                    self.encryption_key = Fernet.generate_key()
                    with open(self.key_file, 'wb') as f:
                        f.write(self.encryption_key)
                    # 设置文件权限（仅所有者可读写）
                    try:
                        os.chmod(self.key_file, 0o600)
                    except:
                        pass  # Windows可能不支持chmod
                
                self.cipher = Fernet(self.encryption_key)
            else:
                # 没有cryptography库，使用简单编码
                self.cipher = None
                self.logger.warning("未安装cryptography库，使用简单编码存储敏感数据")
        except Exception as e:
            self.logger.error(f"初始化加密密钥失败: {str(e)}")
            # 使用简单的base64编码作为备选方案
            self.cipher = None
    
    def _encrypt_sensitive_data(self, data: str) -> str:
        """加密敏感数据"""
        try:
            if self.cipher:
                return self.cipher.encrypt(data.encode()).decode()
            else:
                # 简单的base64编码
                return base64.b64encode(data.encode()).decode()
        except Exception as e:
            self.logger.warning(f"加密数据失败: {str(e)}")
            return data
    
    def _decrypt_sensitive_data(self, encrypted_data: str) -> str:
        """解密敏感数据"""
        try:
            if self.cipher:
                return self.cipher.decrypt(encrypted_data.encode()).decode()
            else:
                # 简单的base64解码
                return base64.b64decode(encrypted_data.encode()).decode()
        except Exception as e:
            self.logger.warning(f"解密数据失败: {str(e)}")
            return encrypted_data
    
    def save_database_configs(self) -> bool:
        """保存数据库配置到文件"""
        try:
            with self.lock:
                configs = db_config_manager.list_configs()
                storage_data = {}
                
                for name, config in configs.items():
                    config_data = {
                        "db_type": config.db_type.value,
                        "host": config.host,
                        "port": config.port,
                        "database": config.database,
                        "username": config.username,
                        "password": self._encrypt_sensitive_data(config.password),
                        "charset": config.charset,
                        "ssl_mode": config.ssl_mode,
                        "connection_timeout": config.connection_timeout,
                        "pool_size": config.pool_size,
                        "max_overflow": config.max_overflow,
                        "pool_timeout": config.pool_timeout,
                        "pool_recycle": config.pool_recycle,
                        "echo": config.echo,
                        "created_at": datetime.now().isoformat(),
                        "last_test_time": None,
                        "last_test_result": None
                    }
                    storage_data[name] = config_data
                
                with open(self.db_config_file, 'w', encoding='utf-8') as f:
                    json.dump(storage_data, f, indent=2, ensure_ascii=False)
                
                self.logger.info(f"数据库配置已保存到 {self.db_config_file}")
                return True
                
        except Exception as e:
            self.logger.error(f"保存数据库配置失败: {str(e)}")
            return False
    
    def load_database_configs(self) -> bool:
        """从文件加载数据库配置"""
        try:
            if not os.path.exists(self.db_config_file):
                self.logger.info("数据库配置文件不存在，跳过加载")
                return True
            
            with open(self.db_config_file, 'r', encoding='utf-8') as f:
                storage_data = json.load(f)
            
            loaded_count = 0
            for name, config_data in storage_data.items():
                try:
                    # 解密密码
                    password = self._decrypt_sensitive_data(config_data["password"])
                    
                    config = DatabaseConfig(
                        db_type=DatabaseType(config_data["db_type"]),
                        host=config_data["host"],
                        port=config_data["port"],
                        database=config_data["database"],
                        username=config_data["username"],
                        password=password,
                        charset=config_data.get("charset", "utf8mb4"),
                        ssl_mode=config_data.get("ssl_mode"),
                        connection_timeout=config_data.get("connection_timeout", 30),
                        pool_size=config_data.get("pool_size", 10),
                        max_overflow=config_data.get("max_overflow", 20),
                        pool_timeout=config_data.get("pool_timeout", 30),
                        pool_recycle=config_data.get("pool_recycle", 3600),
                        echo=config_data.get("echo", False)
                    )
                    
                    db_config_manager.add_config(name, config)
                    loaded_count += 1
                    
                except Exception as e:
                    self.logger.error(f"加载数据库配置 {name} 失败: {str(e)}")
            
            self.logger.info(f"成功加载 {loaded_count} 个数据库配置")
            return True
            
        except Exception as e:
            self.logger.error(f"加载数据库配置失败: {str(e)}")
            return False
    
    def save_ai_configs(self) -> bool:
        """保存AI配置到文件"""
        try:
            with self.lock:
                configs = ai_config_manager.list_configs()
                storage_data = {}
                
                for name, config in configs.items():
                    config_data = {
                        "model_type": config.model_type.value,
                        "model_name": config.model_name,
                        "api_key": self._encrypt_sensitive_data(config.api_key) if config.api_key else None,
                        "api_base": config.api_base,
                        "api_version": config.api_version,
                        "max_tokens": config.max_tokens,
                        "temperature": config.temperature,
                        "timeout": config.timeout,
                        "retry_count": config.retry_count,
                        "local_model_path": config.local_model_path,
                        "device": config.device,
                        "load_in_8bit": config.load_in_8bit,
                        "load_in_4bit": config.load_in_4bit,
                        "torch_dtype": config.torch_dtype,
                        "trust_remote_code": config.trust_remote_code,
                        "created_at": datetime.now().isoformat()
                    }
                    storage_data[name] = config_data
                
                # 保存激活的模型
                storage_data["_meta"] = {
                    "active_model": ai_config_manager.active_model,
                    "saved_at": datetime.now().isoformat()
                }
                
                with open(self.ai_config_file, 'w', encoding='utf-8') as f:
                    json.dump(storage_data, f, indent=2, ensure_ascii=False)
                
                self.logger.info(f"AI配置已保存到 {self.ai_config_file}")
                return True
                
        except Exception as e:
            self.logger.error(f"保存AI配置失败: {str(e)}")
            return False
    
    def load_ai_configs(self) -> bool:
        """从文件加载AI配置"""
        try:
            if not os.path.exists(self.ai_config_file):
                self.logger.info("AI配置文件不存在，跳过加载")
                return True
            
            with open(self.ai_config_file, 'r', encoding='utf-8') as f:
                storage_data = json.load(f)
            
            # 获取元数据
            meta_data = storage_data.pop("_meta", {})
            
            loaded_count = 0
            for name, config_data in storage_data.items():
                try:
                    # 解密API密钥
                    api_key = None
                    if config_data.get("api_key"):
                        api_key = self._decrypt_sensitive_data(config_data["api_key"])
                    
                    config = AIModelConfig(
                        model_type=AIModelType(config_data["model_type"]),
                        model_name=config_data["model_name"],
                        api_key=api_key,
                        api_base=config_data.get("api_base"),
                        api_version=config_data.get("api_version"),
                        max_tokens=config_data.get("max_tokens", 2048),
                        temperature=config_data.get("temperature", 0.7),
                        timeout=config_data.get("timeout", 60),
                        retry_count=config_data.get("retry_count", 3),
                        local_model_path=config_data.get("local_model_path"),
                        device=config_data.get("device", "auto"),
                        load_in_8bit=config_data.get("load_in_8bit", False),
                        load_in_4bit=config_data.get("load_in_4bit", False),
                        torch_dtype=config_data.get("torch_dtype", "auto"),
                        trust_remote_code=config_data.get("trust_remote_code", True)
                    )
                    
                    ai_config_manager.add_config(name, config)
                    loaded_count += 1
                    
                except Exception as e:
                    self.logger.error(f"加载AI配置 {name} 失败: {str(e)}")
            
            # 恢复激活的模型
            if meta_data.get("active_model"):
                ai_config_manager.set_active_model(meta_data["active_model"])
            
            self.logger.info(f"成功加载 {loaded_count} 个AI配置")
            return True
            
        except Exception as e:
            self.logger.error(f"加载AI配置失败: {str(e)}")
            return False
    
    def update_connection_test_result(self, config_name: str, success: bool, error_msg: str = None):
        """更新连接测试结果"""
        try:
            if not os.path.exists(self.db_config_file):
                return
            
            with open(self.db_config_file, 'r', encoding='utf-8') as f:
                storage_data = json.load(f)
            
            if config_name in storage_data:
                storage_data[config_name]["last_test_time"] = datetime.now().isoformat()
                storage_data[config_name]["last_test_result"] = {
                    "success": success,
                    "error_msg": error_msg,
                    "test_time": datetime.now().isoformat()
                }
                
                with open(self.db_config_file, 'w', encoding='utf-8') as f:
                    json.dump(storage_data, f, indent=2, ensure_ascii=False)
                
        except Exception as e:
            self.logger.error(f"更新连接测试结果失败: {str(e)}")
    
    def get_connection_test_results(self) -> Dict[str, Dict]:
        """获取所有连接测试结果"""
        try:
            if not os.path.exists(self.db_config_file):
                return {}
            
            with open(self.db_config_file, 'r', encoding='utf-8') as f:
                storage_data = json.load(f)
            
            results = {}
            for name, config_data in storage_data.items():
                if "last_test_result" in config_data:
                    results[name] = config_data["last_test_result"]
            
            return results
            
        except Exception as e:
            self.logger.error(f"获取连接测试结果失败: {str(e)}")
            return {}


# 全局配置存储实例
config_storage = ConfigStorage()